home *** CD-ROM | disk | FTP | other *** search
- /* pty_bsd.c - routines to allocate ptys - BSD version
-
- Written by: Don Libes, NIST, 2/6/90
-
- Design and implementation of this program was paid for by U.S. tax
- dollars. Therefore it is public domain. However, the author and NIST
- would appreciate credit if this program or parts of it are used.
-
- */
- #include <stdio.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <sys/ioctl.h>
- #include <sys/file.h>
- #include <signal.h>
- #include <setjmp.h>
- #include <errno.h>
- #ifdef EXTERN_ERRNO
- extern int errno;
- #endif
- #include <tcl.h>
- #include "global.h"
- #include "translate.h"
-
- void debuglog();
-
- static char line[] = "/dev/ptyXX";
- static char *tty_type; /* ptr to char [pt] denoting
- whether it is a pty or tty */
- static char *tty_bank; /* ptr to char [p-z] denoting
- which bank it is */
- static char *tty_num; /* ptr to char [0-f] denoting
- which number it is */
-
- static int i_read_errno;/* place to save errno, if i_read() == -1, so it
- doesn't get overwritten before we get to read it */
-
- /* interruptable read */
- static int
- i_read(fd,buffer,length,timeout)
- int fd;
- char *buffer;
- int length;
- double timeout; /* MDW: Mon Jun 22 15:11:40 1992 */
- {
- int cc = -2;
-
- /* since setjmp insists on returning 1 upon longjmp(,0), */
- /* longjmp(,2) instead. */
-
- /* restart read if setjmp returns 0 (first time) or 2. */
- /* abort if setjmp returns 1. */
-
- if (SetAlarm(timeout)) cc = read(fd,buffer,length);
- ClearAlarm();
- i_read_errno = errno; /* errno can be overwritten by the */
- /* time we return */
-
- /*
- alarm(timeout);
- if (1 != setjmp(env)) {
- env_valid = TRUE;
- cc = read(fd,buffer,length);
- }
- env_valid = FALSE;
- i_read_errno = errno;
- alarm(0);
- */
- return(cc);
- }
-
- static void
- pty_stty(s,name)
- char *s; /* args to stty */
- char *name; /* name of pty */
- {
- #define MAX_ARGLIST 10240
- char buf[MAX_ARGLIST]; /* overkill is easier */
-
- /* tell Saber to shut up over confusion of sprintf return type */
- /*SUPPRESS 701*/
- sprintf(buf,"stty %s < %s > %s",s,name,name);
- system(buf);
- }
-
- struct sgttyb exp_tty_original; /* tty parms that include raw/echo */
-
- #define GET_TTYTYPE 0
- #define SET_TTYTYPE 1
- static void
- ttytype(request,fd,s)
- int request;
- int fd;
- char *s; /* stty args, used only if request == SET_TTYTYPE */
- {
- static struct tchars tc; /* special characters */
- static struct ltchars lc; /* local special characters */
- static struct winsize win; /* window size */
- static int lb; /* local modes */
- static int l; /* line discipline */
-
- static int is_a_tty;
-
- if (request == GET_TTYTYPE) {
- if (-1 == ioctl(fd, TIOCGETP, (char *)&exp_tty_original)
- || -1 == ioctl(fd, TIOCGETC, (char *)&tc)
- || -1 == ioctl(fd, TIOCGETD, (char *)&l)
- || -1 == ioctl(fd, TIOCGLTC, (char *)&lc)
- || -1 == ioctl(fd, TIOCLGET, (char *)&lb)
- || -1 == ioctl(fd, TIOCGWINSZ, (char *)&win)) {
- is_a_tty = FALSE;
- } else is_a_tty = TRUE;
- } else { /* type == SET_TTYTYPE */
- if (is_a_tty) {
- (void) ioctl(fd, TIOCSETP, (char *)&exp_tty_original);
- (void) ioctl(fd, TIOCSETC, (char *)&tc);
- (void) ioctl(fd, TIOCSLTC, (char *)&lc);
- (void) ioctl(fd, TIOCLSET, (char *)&lb);
- (void) ioctl(fd, TIOCSETD, (char *)&l);
- (void) ioctl(fd, TIOCSWINSZ, (char *)&win);
- } else {
- /* if running in the background, we have no access */
- /* to a a tty to copy parameters from, so use ones */
- /* supplied by original Makefile */
- #ifdef __SABER__
- #undef DFLT_STTY
- #define DFLT_STTY "sane"
- #endif
- debuglog("getptyslave: (default) stty %s\n",DFLT_STTY);
- pty_stty(DFLT_STTY,line);
- }
- if (s) {
- /* give user a chance to override any terminal parms */
- debuglog("getptyslave: (user-requested) stty %s\n",s);
- pty_stty(s,line);
- }
- }
- }
-
- char lock[] = "/tmp/ptylock.XX"; /* XX is replaced by pty id */
- char locksrc[50] = "/tmp/expect.pid"; /* pid is replaced by real pid */
- /* locksrc is used as the link source, i.e., something to link from */
-
- void
- init_pty()
- {
- tty_type = &line[strlen("/dev/")];
- tty_bank = &line[strlen("/dev/pty")];
- tty_num = &line[strlen("/dev/ptyp")];
- ttytype(GET_TTYTYPE,0,(char *)0);
- sprintf(locksrc,"/tmp/expect.%d",getpid());
- }
-
- /* returns fd of master end of pseudotty */
- int
- getptymaster()
- {
- char *hex;
- struct stat statbuf;
- int master;
- int lfd; /* locksrc file descriptor */
- int locked = 0;
- time_t current_time;
- void (*sigfuncs[32])();
-
- /* MDW: Mon Jun 22 15:15:13 1992 */
- VoidFuncArray init_expect_alarms();
-
- init_expect_alarms(sigfuncs, 1<<SIGALRM);
- /* void (* func)() = Signal(SIGALRM,sigalarm_handler); */
-
- time(¤t_time);
-
- /* recreate locksrc to prevent locks from 'looking old', so that */
- /* they are not deleted (later on in this code) */
- (void) unlink(locksrc);
- if (-1 == (lfd = creat(locksrc,0777))) {
- debuglog("can't create %s, errno = %d\n",locksrc, errno);
- return(-1);
- }
- close(lfd);
-
- for (*tty_bank = 'p';; (*tty_bank)++) {
- *tty_num = '0';
- if (stat(line, &statbuf) < 0) break;
- for (hex = "0123456789abcdef";*hex;hex++) {
- int cc;
- char c;
- int slave;
-
- *tty_num = *hex;
-
- /* make a lock file to prevent others (for now only */
- /* expects) from allocating pty while we are playing */
- /* with it. This allows us to rigorously test the */
- /* pty is usable. */
-
- if (locked) {
- (void) unlink(lock);
- locked = 0;
- }
- sprintf(lock,"/tmp/ptylock.%c%c",*tty_bank,*tty_num);
- if (-1 == (link(locksrc,lock))) {
- /* unlink any real old ones (i.e., > 1 hour) */
- if ((0 == stat(lock,&statbuf)) &&
- (statbuf.st_mtime+3600 < current_time)) {
- (void) unlink(lock);
- }
- continue;
- }
- locked = 1;
-
- /* verify no one else is using slave by attempting */
- /* to read eof from master side */
- *tty_type = 'p';
- if (0 > (master = open(line,O_RDWR))) continue;
- *tty_type = 't';
- if (0 > (slave = open(line,O_RDWR))) {
- (void) close(master);
- continue;
- }
- (void) close(slave);
- cc = i_read(master,&c,1,10.0);
- (void) close(master);
- if (!(cc == 0 || cc == -1)) {
- debuglog("%s slave open, skipping\n",line);
- continue;
- }
-
- /* verify no one else is using master by attempting */
- /* to read eof from slave side */
- *tty_type = 'p';
- if (0 > (master = open(line,O_RDWR))) continue;
- *tty_type = 't';
- if (0 > (slave = open(line,O_RDWR))) {
- (void) close(master);
- continue;
- }
- (void) close(master);
- cc = i_read(slave,&c,1,10.0);
- (void) close(slave);
- if (!(cc == 0 || cc == -1)) {
- debuglog("%s master open, skipping\n",line);
- continue;
- }
-
- /* seems ok, let's use it */
- *tty_type = 'p';
- if (0 > (master = open(line,O_RDWR))) continue;
- *tty_type = 't';
-
- Signal(SIGALRM,sigfuncs[SIGALRM]); /* MDW: Mon Jun 22 15:16:20 1992 */
- /* Signal(SIGALRM,func); */
- (void) unlink(locksrc);
- debuglog("using pty %s\n",line);
- return(master);
- }
- }
- Signal(SIGALRM,sigfuncs[SIGALRM]); /* MDW: Mon Jun 22 15:16:34 1992 */
- /* Signal(SIGALRM,func); */
- unlink(locksrc);
- return(-1);
- }
-
- int
- getptyslave(stty_args)
- char *stty_args;
- {
- int slave;
-
- if (0 > (slave = open(line, O_RDWR))) return(-1);
-
- /* sanity check - if slave not 0, skip rest of this and return */
- /* to what will later be detected as an error in caller */
- if (0 != slave) return(slave);
-
- fcntl(0,F_DUPFD,1); /* duplicate 0 onto 1 to prepare for stty */
- ttytype(SET_TTYTYPE,slave,stty_args);
- (void) unlink(lock);
- return(slave);
- }
-
- #if 0
- opendevtty()
- {
- int fd;
- int p;
-
- errorlog("--opendevtty--\n");
- errorlog("pid = %d\n",getpid());
- errorlog("pgrp = %d\n",getpgrp(0));
- ioctl(0,TIOCGPGRP,&p);
- errorlog("tgrp(0) = %d\n",p);
- if (-1 == (fd = open("/dev/tty",2))) {
- perror("open"); errorlog("sanity open failed\n");
- } else errorlog("sanity open succeeded\n");
- }
- #endif
-